<template>
  <div class="wrap">
    <div class="header">
      <div class="title">
        <h2>{{ this.data.name }}</h2>
        <p>{{ this.data.description }}</p>
      </div>
      <div class="handle">
        <div class="item">
          <a-dropdown-button @click="refreshClick">
            <a-icon type="redo" />{{ refresh.current.name }}刷新
            <a-menu slot="overlay" @click="refreshMenuClick">
              <a-menu-item :key="item.value" v-for="item in refresh.list">
                {{ item.name }}
              </a-menu-item>
            </a-menu>
            <a-icon slot="icon" type="down" />
          </a-dropdown-button>
        </div>

        <div class="item">
          <a-range-picker
            v-model="date.current.ranges"
            :ranges="date.ranges"
            show-time
            format="YYYY/MM/DD HH:mm:ss"
            @change="changeDatePicker"
            @ok="submitDatePicker"
            style="display: inline"
          >
            <a-button icon="calendar"> {{ date.current.ranges ? date.current.name : '请选择' }} </a-button>
            <a-icon slot="suffixIcon" type="calendar" />
          </a-range-picker>
        </div>
        <a-button class="item" type="primary" icon="plus" @click="showLogChartListModal()"> 添加图表 </a-button>
        <a-button class="item" icon="fullscreen" @click="fullScreen()"></a-button>
      </div>
    </div>
    <div class="body" id="girdContainer">
      <div class="gird-header" v-if="isAllFullScreen">
        <h1>{{ this.data.name }}</h1>
        <span>{{ this.data.description }}</span>
      </div>
      <!-- 一排分成12分 -->
      <grid-layout
        :layout.sync="layout"
        :col-num="12"
        :row-height="30"
        :is-draggable="true"
        :is-resizable="true"
        :is-mirrored="false"
        :vertical-compact="true"
        :margin="[15, 15]"
        :use-css-transforms="true"
        @layout-updated="layoutUpdatedEvent"
        class="grid-layout"
      >
        <grid-item
          v-for="item in layout"
          :x="item.x"
          :y="item.y"
          :w="item.w"
          :h="item.h"
          :i="item.i"
          :key="item.i"
          drag-allow-from=".vue-draggable-handle"
          drag-ignore-from=".no-drag"
          @resized="resizedEvent"
          @container-resized="containerResizedEvent"
          class="grid-item"
        >
          <div class="grid-item-header">
            <div class="vue-draggable-handle title">
              <a-tooltip placement="topLeft">
                <template slot="title"> 按住鼠标左键拖拽 </template>
                <template v-if="item.resource">
                  {{ item.resource.name }}
                </template>
              </a-tooltip>
              <p class="time" v-if="item.date.name == '自定义'">
                {{ item.date.name }}
                <a-tooltip>
                  <template slot="title">
                    开始时间：{{ moment(item.date.ranges[0]).format('YYYY-MM-DD HH:mm:ss') }} 结束时间：{{
                      moment(item.date.ranges[1]).format('YYYY-MM-DD HH:mm:ss')
                    }}
                  </template>
                  <a-icon type="info-circle" />
                </a-tooltip>
              </p>
              <p class="time" v-else>{{ item.date.name }}</p>
            </div>
            <div class="handle">
              <div class="item">
                <a-range-picker
                  v-model="item.date.ranges"
                  :ranges="date.ranges"
                  show-time
                  format="YYYY/MM/DD HH:mm:ss"
                  @change="changeSingleDatePicker"
                  @ok="submitSingleDatePicker(item, item.date.ranges)"
                  style="display: inline"
                >
                  <!-- <a-button icon="calendar"> {{ date.current.ranges ? date.current.name : '请选择' }} </a-button> -->
                  <a-icon type="calendar" title="选择时间" class="icon-calendar" />
                  <a-icon slot="suffixIcon" type="calendar" />
                </a-range-picker>
              </div>
              <div class="item">
                <a-dropdown class="handle-more">
                  <span class="ant-dropdown-link" @click="(e) => e.preventDefault()">
                    <b><a-icon type="ellipsis" /></b>
                  </span>
                  <a-menu slot="overlay">
                    <a-menu-item>
                      <a href="javascript:;" class="grid-dropdown-a"><a-icon type="setting" />设置</a>
                    </a-menu-item>
                    <a-menu-item>
                      <a
                        href="javascript:;"
                        class="grid-dropdown-a"
                        @click="download(item)"
                      ><a-icon type="download" />下载</a
                      >
                    </a-menu-item>
                    <a-menu-item>
                      <a href="javascript:;" class="grid-dropdown-a" @click="removeRows(item.i)">
                        <a-icon type="delete" />删除
                      </a>
                    </a-menu-item>
                  </a-menu>
                </a-dropdown>
              </div>
            </div>
          </div>
          <div class="grid-item-body no-drag">
            <!-- <span>{{ item.chartId }} | {{ item.i }}</span> -->
            <div class="echarts" :id="'chart' + item.i"></div>
          </div>
        </grid-item>
      </grid-layout>
    </div>

    <log-chart-list-modal ref="logChartListModal"></log-chart-list-modal>
  </div>
</template>

<script>
import moment from 'moment'
import _ from 'lodash'
import { downloadFile } from '@/utils/commonUtil'
import { getDashBoardById, editDashBoard } from '@/api/dashboard'
import { sqlFindOne } from '@/api/sql'
import { esSearch } from '@/api/es'
import { GridLayout, GridItem } from 'vue-grid-layout'
import LogChartListModal from './modules/logChartListModal'
import { start } from 'nprogress'

export default {
  name: 'DashboardDetail',
  components: {
    LogChartListModal,
    GridLayout,
    GridItem
  },
  data () {
    return {
      time2: undefined,
      id: null,
      // 刷新
      refresh: {
        current: { name: '5秒', value: 5 },
        list: [
          { name: '暂停', value: 0 },
          { name: '5秒', value: 5 },
          { name: '10秒', value: 10 },
          { name: '20秒', value: 20 },
          { name: '30秒', value: 30 },
          { name: '45秒', value: 45 },
          { name: '60秒', value: 60 },
          { name: '2分钟', value: 120 },
          { name: '5分钟', value: 360 },
          { name: '10分钟', value: 600 }
        ],
        // 定时器
        timer: null
      },

      // 时间选择
      date: {
        current: {
          name: '今天',
          ranges: [moment().startOf('days'), moment()]
        },
        ranges: {
          前5分钟: [moment().subtract(5, 'minute'), moment()],
          前15分钟: [moment().subtract(15, 'minute'), moment()],
          前30分钟: [moment().subtract(30, 'minute'), moment()],
          前60分钟: [moment().subtract(1, 'hour'), moment()],
          前3小时: [moment().subtract(3, 'hour'), moment()],
          前4小时: [moment().subtract(4, 'hour'), moment()],
          前6小时: [moment().subtract(6, 'hour'), moment()],
          前12小时: [moment().subtract(12, 'hour'), moment()],
          前24小时: [moment().subtract(1, 'day'), moment()],
          过去3天: [moment().subtract(3, 'day').startOf('days'), moment().subtract(3, 'day').endOf('days')],
          过去7天: [moment().subtract(7, 'day').startOf('days'), moment().subtract(7, 'day').endOf('days')],
          过去30天: [moment().subtract(30, 'day').startOf('days'), moment().subtract(30, 'day').endOf('days')],
          今天: [moment().startOf('days'), moment()],
          本周: [moment().startOf('week'), moment()],
          本月: [moment().startOf('month'), moment()],
          昨天: [moment().subtract(1, 'day').startOf('days'), moment().subtract(1, 'day').endOf('days')],
          前天: [moment().subtract(2, 'day').startOf('days'), moment().subtract(2, 'day').endOf('days')],
          上周: [moment().subtract(1, 'weeks').startOf('week'), moment().subtract(1, 'weeks').endOf('week')],
          上月: [moment().subtract(1, 'months').startOf('months'), moment().subtract(1, 'months').endOf('months')]
        }
      },
      // 布局
      layout: [],
      // 仪表数据
      data: {},
      layoutIndex: 0,
      // 删除标记，为true才提示消息
      removeRowsFlag: false,
      // 全屏标记
      isAllFullScreen: false
    }
  },

  created () {
    // 添加图表到视图中
    this.$bus.on('selectedChart', (data) => {
      console.log('selectedChart', data)
      // 添加一行
      this.addRows(data)
    })
  },

  mounted () {
    this.id = this.$route.query.id
    console.log(this.id)
    this.getData(this.id)
    // 全屏事件监听
    document.addEventListener('fullscreenchange', this.fullScreenChange)
  },

  beforeDestroy () {
    // 销毁监听事件，防止多次触发
    this.$bus.$off('selectedChart')
  },

  /**
   * 页面卸载
   */
  destroyed () {
    document.removeEventListener('fullscreenchange', this.fullScreenChange)
  },

  methods: {
    moment,
    /**
     * change全局时间
     */
    changeDatePicker (value, dateString) {
      console.log('Selected Time: ', value)
      console.log('Formatted Selected Time: ', dateString)
    },

    /**
     * 选择全局时间后，计算选择的时间，挑选格式
     */
    submitDatePicker (values) {
      console.log('onOk: ', values)
      var status = true
      for (const i in this.date.ranges) {
        const item = this.date.ranges[i]
        if (values[0] === item[0] && values[1] === item[1]) {
          console.log(i)
          this.date.current.name = i
          status = false
        }
      }
      // 没找到
      if (status) {
        this.date.current.name = '自定义'
      }

      // 手动选择时间后，所用的图表都刷新一遍，并且储存到数据库
      // this.data.dateRange = JSON.stringify(this.date.current)

      // console.log('this.data.dateRange', this.data.dateRange)
      console.log('this.date.current', JSON.stringify(this.date.current))

      // 所有图表时间都更新
      this.layout.forEach((item) => {
        item.date = this.date.current
      })

      // 储存到数据库
      this.save(this.data, this.layout)
      // 图表刷新
      setTimeout(() => {
        this.getData(this.id)
      }, 1000)
    },

    /**
     * 改变单个时间
     */
    changeSingleDatePicker (value, dateString) {
      console.log('Selected Time: ', value)
      console.log('Formatted Selected Time: ', dateString)
    },

    /**
     * 选择单个时间
     */
    submitSingleDatePicker (row, values) {
      console.log('选择单个时间', row, values)
      var status = true
      for (const i in this.date.ranges) {
        const item = this.date.ranges[i]
        if (values[0] === item[0] && values[1] === item[1]) {
          console.log(i)
          row.date.name = i
          status = false
        }
      }
      // 没找到
      if (status) {
        row.date.name = '自定义'
      }
      console.log('row', row)
      // 储存到数据库
      this.save(this.data, this.layout)
      // 重新加载数据
      this.getChart(row)
    },

    /**
     * 获取数据
     */
    getData (id) {
      getDashBoardById({ id: id }).then((res) => {
        this.data = res
        this.layout = JSON.parse(res.layout)
        // 初始化刷新时间
        this.refreshMenuClick({ key: this.data.refreshTime, initLoading: true })
        // 获取布局的长度,加一个
        this.layoutIndex = this.layout.length + 1
        // 初始化全局时间
        if (this.data.dateRange) {
          this.date.current = JSON.parse(this.data.dateRange)
        } else {
          this.date.current = { name: '今天', ranges: [moment().startOf('days'), moment()] }
        }
        this.$forceUpdate()
        console.log('this.date.current', this.date.current)
        console.log(this.data)
        this.getAllChart(this.layout)
      })
    },

    /**
     * 获取全部的图表数据,根据chartId获取到每条图表的信息
     * 拿每条图表的信息，柱状Echart
     */
    getAllChart (layout) {
      if (!layout.length) return
      // 循环加载图表
      layout.forEach((item) => {
        this.getChart(item)
      })
    },

    /**
     * 点击，立即刷新一次
     */
    refreshClick (e) {
      console.log('click left button', e)
      this.getData(this.id)
    },

    /**
     * 选择后，暂定定时器，重启定时器
     */
    refreshMenuClick (e) {
      console.log('click', e)
      if (e.key === undefined) return
      const current = this.refresh.list.filter((item) => item.value === e.key)[0]
      this.refresh.current = current
      console.log(current)
      // 本次操作，都要停止定时器，在重启
      clearInterval(this.timer)
      // 首次加载，不需要储存，手动选择的需要储存
      if (!e.initLoading) {
        this.data.refreshTime = this.refresh.current.value
        this.save(this.data, this.layout)
      }
      // 选择暂停刷新
      if (!this.refresh.current.value) return
      // 其他选择
      this.timer = setInterval(() => {
        console.log(`启动定时器，${this.refresh.current.value}秒刷新一次`)
        this.getData(this.id)
      }, this.refresh.current.value * 1000)
    },

    /**
     * 展示图表
     */
    showLogChartListModal () {
      this.$refs.logChartListModal.init()
    },

    /**
     * 只负责储存，数据处理到其他地方完成
     * 储存布局
     */
    save (result, layout) {
      console.log(result)
      // 没有布局数据，暂停执行
      if (!result.id) return
      const layoutCache = []
      // 提layout数据
      layout.forEach((item) => {
        layoutCache.push({
          x: item.x,
          y: item.y,
          w: item.w,
          h: item.h,
          i: item.i,
          chartId: item.chartId,
          resource: item.resource,
          date: item.date
        })
      })

      var params = _.cloneDeep(result)
      // 提取dateRange
      params.dateRange = JSON.stringify(this.date.current)
      console.log('save params', params)
      // 组装layout数据
      params.layout = JSON.stringify(layoutCache)
      editDashBoard(params).then((res) => {
        if (this.removeRowsFlag) {
          this.$notification['success']({
            message: '提示',
            description: '数据删除成功'
          })
          this.removeRowsFlag = false
        } else {
          console.log('触发布局，静默更新成功，不提示消息')
        }
      })
    },

    /**
     * 布局更新时，触发事件
     */
    layoutUpdatedEvent (newLayout) {
      console.log('Updated layout: ', newLayout)
      // 储存数据
      this.save(this.data, newLayout)
    },

    /**
     * 新增行
     */
    addRows (record) {
      console.log(record)
      // 循环添加数据
      record.forEach((item) => {
        console.log('item', item)
        var parameter = JSON.parse(item.parameter)
        var row = {
          x: (this.layout.length * 2) % 12,
          y: this.layout.length + 12,
          w: 12,
          h: 6,
          i: this.layoutIndex,
          chartId: item.id,
          resource: item,
          // 单个选择的时间，全部选择后，单个的图表都要刷新，每个单独的图表加载单独的时间，相互独立不影响彼此
          date: {
            name: '自定义',
            ranges: [moment(parameter.date.start), moment(parameter.date.end)]
          }
        }
        // 在最后添加一行
        this.layout.push(row)
        console.log('addRows', row)
        // 单个图表渲染
        this.getChart(row)
        this.layoutIndex++
      })
    },

    /**
     * 删除行
     */
    removeRows (layoutIndex) {
      this.$confirm({
        title: '提示',
        content: '确定删除数据吗?',
        okText: '确定',
        cancelText: '取消',
        onOk: () => {
          console.log('OK')
          const index = this.layout.map((item) => item.i).indexOf(layoutIndex)
          this.layout.splice(index, 1)
          this.removeRowsFlag = true
        },
        onCancel () {
          console.log('Cancel')
        }
      })
    },

    /**
     * grid改大小，echarts同步更新大小
     */
    resizedEvent (i, newH, newW, newHPx, newWPx) {
      const row = this.layout.filter((item) => item.i === i)[0]
      row.echart.resize()
    },

    /**
     * 网页改变大小，echarts同步更新大小
     */
    containerResizedEvent (i, newH, newW, newHPx, newWPx) {
      const row = this.layout.filter((item) => item.i === i)[0]
      row.echart && row.echart.resize()
    },

    /**
     * 组装单个图表
     */
    async getChart (row) {
      // 获取图表详情
      row.resource = await this.getLogChartById(row.chartId)
      console.log('row.resource', row)
      // 去es查询数据
      const chartData = await this.getChartData(this.data, row.resource.parameter, row)
      console.log('chartData', chartData)

      // 追加了数据，强制刷新视图
      this.$forceUpdate()

      setTimeout(() => {
        row.echart = this.$echarts.init(document.getElementById('chart' + row.i))
        row.echart.showLoading()
        // 拿到es数据，去组装echarts图表
        const option = this.getChartOption(chartData, row.resource.parameter)
        row.echart.setOption(option, true)
        row.echart.hideLoading()
        row.echart.resize()
        window.onresize = function () {
          row.echart.resize()
        }
      }, 1500)
    },

    /**
     * 构建图表
     */
    getChartOption (resource, parameter) {
      console.log('getChartOption', resource)
      var buckets = resource.aggregations.event.buckets
      const option = {
        title: {},
        tooltip: {},
        legend: {
          show: true,
          data: [parameter.chart.field]
        },
        grid: {
          left: '5%',
          right: '4%',
          bottom: '20%',
          top: '15%'
        },
        dataZoom: [
          {
            type: 'inside'
          },
          {
            type: 'inside'
          }
        ],
        xAxis: {
          splitLine: {
            show: false
          },
          data: []
        },
        yAxis: {
          splitLine: {
            show: false
          }
        },
        series: [
          {
            name: parameter.chart.field,
            type: parameter.chartType,
            itemStyle: {
              normal: {
                color: ['#1b89fa']
              }
            },
            data: []
          }
        ]
      }

      buckets.forEach((item) => {
        var date = moment(item.key).format('YYYY-MM-DD HH:mm:ss')
        option.xAxis.data.push(date)
        option.series[0].data.push(item.doc_count)
      })

      return option
    },

    /**
     * 获取数据
     * 根据自己的时间展示数据
     * 全局有时间
     * 自己也有时间
     *
     * 全局时间修改，所有子元素时间都更新和全局时间一样，共享给子元素
     * 单个时间修改，只更新自己的时间
     */
    async getChartData (dashboardData, parameter, row) {
      console.log('dashboardData', dashboardData)
      console.log('result', parameter)
      console.log('row', row)
      let dateRange = null
      // 自己有时间，用自己的时间
      // 否则，用全局的时间
      // 否则，用原始自带时间
      // if (dashboardData.dateRange) {
      //   var dateRangeCache = JSON.parse(dashboardData.dateRange)
      //   dateRange = { start: dateRangeCache.ranges[0], end: dateRangeCache.ranges[1] }
      // } else {
      //   dateRange = parameter.date
      // }
      if (row.date) {
        dateRange = { start: row.date.ranges[0], end: row.date.ranges[1] }
      } else if (dashboardData.dateRange) {
        var dateRangeCache = JSON.parse(dashboardData.dateRange)
        dateRange = { start: dateRangeCache.ranges[0], end: dateRangeCache.ranges[1] }
      } else {
        dateRange = parameter.date
      }

      const params = {
        url: `elastic/${parameter.url}/_search`,
        query: {
          size: 0,
          query: {
            constant_score: {
              filter: {
                range: {
                  timestamp: {
                    gte: dateRange.start,
                    lte: dateRange.end
                  }
                }
              }
            }
          },
          aggs: {
            event: {
              date_histogram: {
                field: parameter.chart.field,
                interval: parameter.chart.interval,
                min_doc_count: 0,
                extended_bounds: {
                  min: dateRange.start,
                  max: dateRange.end
                }
              }
            }
          }
        }
      }
      return new Promise((resolve, reject) => {
        esSearch(params).then(
          (res) => {
            console.log(res)
            resolve(res)
          },
          (error) => {
            reject(error)
          }
        )
      })
    },

    /**
     * 获取图表详情
     */
    async getLogChartById (id) {
      const params = {
        sql: `select * from t_log_chart where id=${id}`
      }
      return new Promise((resolve, reject) => {
        sqlFindOne(params).then(
          (res) => {
            try {
              res.parameter = JSON.parse(res.parameter)
            } catch (e) {
              res.parameter = {}
              console.error(e)
            }
            resolve(res)
          },
          (error) => {
            console.log(error)
            resolve(error)
          }
        )
      })
    },

    /**
     * 全屏
     */
    fullScreen () {
      const element = document.getElementById('girdContainer')
      console.log(element)
      if (element.requestFullscreen) {
        element.requestFullscreen()
      } else if (element.msRequestFullscreen) {
        element.msRequestFullscreen()
      } else if (element.mozRequestFullScreen) {
        element.mozRequestFullScreen()
      } else if (element.webkitRequestFullscreen) {
        element.webkitRequestFullscreen()
      }
      // this.isAllFullScreen = true
    },

    // /**
    //  * 退出全屏
    //  */
    // exitFullscreen () {
    //   if (document.exitFullscreen) {
    //     document.exitFullscreen()
    //   } else if (document.msExitFullscreen) {
    //     document.msExitFullscreen()
    //   } else if (document.mozCancelFullScreen) {
    //     document.mozCancelFullScreen()
    //   } else if (document.webkitExitFullscreen) {
    //     document.webkitExitFullscreen()
    //   }
    //   this.isFullScreen = false
    // }
    /**
     * 全屏事件监听
     */
    fullScreenChange () {
      this.isAllFullScreen = !!document.fullscreenElement
    },

    /**
     * 下载单个图表
     */
    download (record) {
      setTimeout(() => {
        var chartImgUrl = record.echart.getDataURL({
          pixelRatio: 2,
          backgroundColor: '#fff'
        })
        downloadFile(`${record.resource.name}.png`, chartImgUrl)
      }, 100)
    }
  }
}
</script>

<style lang="less" scoped>
.wrap {
}
.header {
  background: #fff;
  padding: 10px 10px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  border: 1px solid #eee;
  .title {
    width: 50%;
    h2 {
      font-size: 16px;
      font-weight: bold;
      margin: 0;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    p {
      margin: 0;
      overflow: hidden;
      white-space: nowrap;
      text-overflow: ellipsis;
    }
  }
  .handle {
    width: 50%;
    display: flex;
    justify-content: flex-end;
    align-items: center;
    .item {
      margin-left: 10px;
    }
  }
}
.body {
  background: #f0f2f5;
  .gird-header {
    text-align: center;
    padding-top: 20px;
    h1 {
      font-size: 24px;
    }
    span {
      font-size: 16px;
    }
  }
  .grid-layout {
    margin: 0 -15px;
    touch-action: none;
    .grid-item {
      background: #fff;
      border: 1px solid #eee;
    }

    .grid-item-header {
      display: flex;
      justify-content: space-between;
      align-content: center;
      width: 100%;
      padding: 6px 10px 0;
      background-color: #fff;
      // border-bottom: 1px solid #eee;
      position: relative;
      z-index: 99;
      .title {
        cursor: move;
        color: #000;
        width: 30%;
        overflow: hidden;
        text-overflow: ellipsis;
        word-break: keep-all;
        white-space: nowrap;
        .time {
          padding: 0;
          margin: 0;
          font-size: 12px;
          color: #999;
        }
      }
      .handle {
        width: 70%;
        display: flex;
        justify-content: flex-end;
        align-content: center;
        > div {
          margin-right: 6px;
        }
        /deep/.icon-calendar {
          cursor: pointer;
        }
      }
    }
    .grid-item-body {
      height: 100%;
      overflow: hidden;
      position: absolute;
      top: 0;
      bottom: 0;
      padding-top: 46px;
      left: 0;
      right: 0;
      .echarts {
        width: 100%;
        height: 100%;
      }
    }
  }
}
.grid-dropdown-a {
  font-size: 13px;
  i {
    margin-right: 4px;
  }
}
</style>
